// 归档历史行情
// https://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1815_stock&TABKEY=tab1&PAGENO=2&txtBeginDate=1990-12-01
use serde::{
    de::{self, Visitor},
    Deserialize, Deserializer, Serialize,
};
use std::fs::File;
use std::io::BufReader;

use anyhow::{ensure, Result};

#[derive(Debug, Serialize, Deserialize)]
pub struct LiShiGuiDangHangQin {
    pub metadata: Metadata,
    pub data: Vec<DataItem>,
}

#[derive(Debug, Serialize)]
pub struct DataItem {
    pub jyrq: String,
    pub zqdm: String,
    pub zqjc: String,
    pub qss: f64,
    pub ks: f64,
    pub zg: f64,
    pub zd: f64,
    pub ss: f64,
    pub sdf: f64,
    pub cjgs: f64,
    pub cjje: f64,
    pub syl1: f64,
}

impl<'de> Deserialize<'de> for DataItem {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct DataItemVisitor;

        impl<'de> Visitor<'de> for DataItemVisitor {
            type Value = DataItem;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("struct DataItem")
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: de::MapAccess<'de>,
            {
                let mut jyrq = None;
                let mut zqdm = None;
                let mut zqjc = None;
                let mut qss = None;
                let mut ks = None;
                let mut zg = None;
                let mut zd = None;
                let mut ss = None;
                let mut sdf = None;
                let mut cjgs = None;
                let mut cjje = None;
                let mut syl1 = None;

                while let Some(key) = map.next_key::<String>()? {
                    match key.as_str() {
                        "jyrq" => jyrq = Some(map.next_value::<String>()?),
                        "zqdm" => zqdm = Some(map.next_value::<String>()?),
                        "zqjc" => zqjc = Some(map.next_value::<String>()?),
                        "qss" => {
                            let v_str: String = map.next_value()?;
                            qss = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }

                        "ks" => {
                            let v_str: String = map.next_value()?;
                            ks = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }

                        "zg" => {
                            let v_str: String = map.next_value()?;
                            zg = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "zd" => {
                            let v_str: String = map.next_value()?;
                            zd = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "ss" => {
                            let v_str: String = map.next_value()?;
                            ss = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "sdf" => {
                            let v_str: String = map.next_value()?;
                            sdf = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "cjgs" => {
                            let v_str: String = map.next_value()?;
                            cjgs = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "cjje" => {
                            let v_str: String = map.next_value()?;
                            cjje = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        "syl1" => {
                            let v_str: String = map.next_value()?;
                            syl1 = Some(
                                v_str
                                    .replace(",", "")
                                    .parse::<f64>()
                                    .map_err(de::Error::custom)?,
                            );
                        }
                        _ => {
                            let _ = map.next_value::<serde::de::IgnoredAny>();
                        }
                    }
                }

                Ok(DataItem {
                    jyrq: jyrq.ok_or_else(|| de::Error::missing_field("jyrq"))?,
                    zqdm: zqdm.ok_or_else(|| de::Error::missing_field("zqdm"))?,
                    zqjc: zqjc.ok_or_else(|| de::Error::missing_field("zqjc"))?,
                    qss: qss.ok_or_else(|| de::Error::missing_field("qss"))?,
                    ks: ks.ok_or_else(|| de::Error::missing_field("ks"))?,
                    zg: zg.ok_or_else(|| de::Error::missing_field("zg"))?,
                    zd: zd.ok_or_else(|| de::Error::missing_field("zd"))?,
                    ss: ss.ok_or_else(|| de::Error::missing_field("ss"))?,
                    sdf: sdf.ok_or_else(|| de::Error::missing_field("sdf"))?,
                    cjgs: cjgs.ok_or_else(|| de::Error::missing_field("cjgs"))?,
                    cjje: cjje.ok_or_else(|| de::Error::missing_field("cjje"))?,
                    syl1: syl1.ok_or_else(|| de::Error::missing_field("syl1"))?,
                })
            }
        }

        deserializer.deserialize_map(DataItemVisitor)
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Metadata {
    pub catalogid: String,
    pub name: String,
    pub excel: String,
    pub pagetype: String,
    pub subname: String,
    pub tabkey: String,
    pub pagesize: u32,
    pub pageno: u32,
    pub pagecount: u32,
    pub recordcount: u32,
}

pub fn json_file(path: &str) {
    println!("\n\n****** parse json file: {}\n", path);

    // Open the JSON path and read its contents
    let path = File::open(path).expect(&format!("Failed to open path={}", path));
    let reader = BufReader::new(path);

    // Parse the JSON data into the Data struct
    let hangqin_vec: Vec<LiShiGuiDangHangQin> =
        serde_json::from_reader(reader).expect("Failed to parse JSON");

    // Print the parsed data for demonstration
    println!("hangqin_vec={:#?} ", hangqin_vec);

    // Get the first DataItem from the parsed data
    if let Some(hq) = hangqin_vec.iter().next() {
        println!("metadata: {:?}", hq.metadata);
        println!("Data: {:?}", hq.data);
    } else {
        println!("No DataItem found in the parsed data.");
    }
}

pub async fn gui_dang_hang_qing() -> Result<()> {
    // GET /api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1815_stock&TABKEY=tab1&PAGENO=1&tab1PAGESIZE=30&txtBeginDate=2022-01-28&radioClass=00%2C20%2C30%2CC6%2CC7%2CGE%2C14&txtSite=all&random=0.7112586268274617 HTTP/1.1
    // Accept: application/json, text/javascript, */*; q=0.01
    // Accept-Encoding: gzip, deflate, br
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    // Connection: keep-alive
    // Content-Type: application/json
    // Host: www.szse.cn
    // Referer: https://www.szse.cn/market/trend/archive/index.html
    // Sec-Fetch-Dest: empty
    // Sec-Fetch-Mode: cors
    // Sec-Fetch-Site: same-origin
    // User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
    // X-Request-Type: ajax
    // X-Requested-With: XMLHttpRequest
    // sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
    // sec-ch-ua-mobile: ?0
    // sec-ch-ua-platform: "macOS"

    let request_url = "https://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1815_stock&TABKEY=tab1&PAGENO=1&tab1PAGESIZE=30&txtBeginDate=2022-01-28";
    let response = REQWEST_CLIENT.get(request_url)
        .header(reqwest::header::ACCEPT, "application/json, text/javascript, */*; q=0.01")
        .header("Accept-Encoding", "gzip, deflate, br")
        .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
        .header("Connection", "keep-alive")
        .header("Content-Type", "application/json")
        .header("Host", "www.szse.cn")
        .header("Referer", "https://www.szse.cn/market/trend/archive/index.html")
        .header("Sec-Fetch-Dest", " empty")
        .header("Sec-Fetch-Mode", " cors")
        .header("Sec-Fetch-Site", " same-origin")
        .header("User-Agent", " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36")
        .header("X-Request-Type", " ajax")
        .header("X-Requested-With", " XMLHttpRequest")
        .header("sec-ch-ua", " \"Not A(Brand\";v=\"99\", \"Google Chrome\";v=\"121\", \"Chromium\";v=\"121\"")
        .header("sec-ch-ua-mobile", " ?0")
        .header("sec-ch-ua-platform", " \"macOS\"")
        .send()
        .await?;

    let body = response.text().await?;

    println!("*** body={}", body);
    let hangqin_vec: Vec<LiShiGuiDangHangQin> = serde_json::from_str(&body)?;

    println!("{:?}", hangqin_vec);

    Ok(())
}

pub async fn hang_qing() -> Result<()> {
    // GET /api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1815_stock_snapshot&TABKEY=tab1&PAGENO=2&tab1PAGESIZE=10&txtBeginDate=2024-02-08&txtEndDate=2024-02-08&archiveDate=2022-02-07&random=0.8786228249620156 HTTP/1.1
    // Accept: application/json, text/javascript, */*; q=0.01
    // Accept-Encoding: gzip, deflate, br
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    // Connection: keep-alive
    // Content-Type: application/json
    // Host: www.szse.cn
    // Referer: https://www.szse.cn/market/trend/index.html
    // Sec-Fetch-Dest: empty
    // Sec-Fetch-Mode: cors
    // Sec-Fetch-Site: same-origin
    // User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
    // X-Request-Type: ajax
    // X-Requested-With: XMLHttpRequest
    // sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
    // sec-ch-ua-mobile: ?0
    // sec-ch-ua-platform: "macOS"

    let request_url = "https://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1815_stock_snapshot&TABKEY=tab1&PAGENO=2&tab1PAGESIZE=10&txtBeginDate=2024-02-08&txtEndDate=2024-02-08&archiveDate=2022-02-07";
    let response = REQWEST_CLIENT.get(request_url)
        .header(reqwest::header::ACCEPT, "application/json, text/javascript, */*; q=0.01")
        .header("Accept-Encoding", "gzip, deflate, br")
        .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
        .header("Connection", "keep-alive")
        .header("Content-Type", "application/json")
        .header("Host", "www.szse.cn")
        .header("Referer", "https://www.szse.cn/market/trend/index.html")
        .header("Sec-Fetch-Dest", " empty")
        .header("Sec-Fetch-Mode", " cors")
        .header("Sec-Fetch-Site", " same-origin")
        .header("User-Agent", " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36")
        .header("X-Request-Type", " ajax")
        .header("X-Requested-With", " XMLHttpRequest")
        .header("sec-ch-ua", " \"Not A(Brand\";v=\"99\", \"Google Chrome\";v=\"121\", \"Chromium\";v=\"121\"")
        .header("sec-ch-ua-mobile", " ?0")
        .header("sec-ch-ua-platform", " \"macOS\"")
        .send()
        .await?;

    let body = response.text().await?;

    println!("*** body={}", body);
    let hangqin_vec: Vec<LiShiGuiDangHangQin> = serde_json::from_str(&body)?;

    println!("{:?}", hangqin_vec);

    Ok(())
}
